iFrame Integration Guide
This document will guide you on how to correctly integrate the Connected Payments iFrame to begin accepting payments.
What you'll need:
configId- Your iFrame configuration IDuserName- Your Connected Payments username with transaction permissionssecretKey- Your shared secret key (for HMAC generation)- HTTPS-enabled website (for embedded iFrames)
Choose your integration:
- Hosted iFrame - Full-page redirect for traditional checkout flows
- Embedded iFrame - In-page payment form for seamless experiences
Code samples: Code samples within this document are provided for reference purposes only and are not intended for production use.
How it works
Flow:
- Customer initiates checkout on your site
- Your server generates HMAC-signed URL with payment parameters
- Connected Payments validates signature and renders secure payment form
- Customer enters payment details (card data never touches your server)
- Payment is processed through the payment network
- Result delivered via webhook (authoritative), redirect, or PostMessage
Quick start
Step 1: Generate HMAC signature
Every payment request requires a verifyMessage — an HMAC-SHA256 signature that proves the URL was created by your server and hasn't been tampered with. Connected Payments validates this on every request.
How to generate it:
- Collect the required parameters for your payment request (see the code examples below)
- Join each parameter as a
key=valuepair, separated by& - Hash the resulting string using HMAC-SHA256 with your
secretKey - Append the output as
verifyMessageto your iFrame URL
Never generate the verifyMessage in client-side code — doing so would expose your secretKey. Always perform this step on your server.
Node.js
const crypto = require("crypto");
// Required parameters
const params = {
configId: "5f06c5f5-d4cb-483b-b0b2-242f48516dc5",
userName: "merchant.iframes",
txnType: 1,
merchReference: "ORDER-12345",
amount: 1000, // cents
};
// Create parameter string
const paramString = `configId=${params.configId}&userName=${params.userName}&txnType=${params.txnType}&merchReference=${params.merchReference}&amount=${params.amount}`;
// Generate HMAC
const verifyMessage = crypto
.createHmac("sha256", process.env.CONNECTED_PAYMENTS_SECRET_KEY)
.update(paramString)
.digest("hex");
PHP
$params = [
'configId' => '5f06c5f5-d4cb-483b-b0b2-242f48516dc5',
'userName' => 'merchant.iframes',
'txnType' => 1,
'merchReference' => 'ORDER-12345',
'amount' => 1000
];
$paramString = http_build_query($params);
$verifyMessage = hash_hmac('sha256', $paramString, getenv('CONNECTED_PAYMENTS_SECRET_KEY'));
Python
import hmac
import hashlib
import os
params = {
'configId': '5f06c5f5-d4cb-483b-b0b2-242f48516dc5',
'userName': 'merchant.iframes',
'txnType': 1,
'merchReference': 'ORDER-12345',
'amount': 1000
}
param_string = '&'.join([f"{k}={v}" for k, v in params.items()])
verify_message = hmac.new(
os.getenv('CONNECTED_PAYMENTS_SECRET_KEY').encode(),
param_string.encode(),
hashlib.sha256
).hexdigest()
C#
using System.Security.Cryptography;
using System.Text;
string paramString = "configId=5f06c5f5-d4cb-483b-b0b2-242f48516dc5&userName=merchant.iframes&txnType=1&merchReference=ORDER-12345&amount=1000";
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(Environment.GetEnvironmentVariable("CONNECTED_PAYMENTS_SECRET_KEY"))))
{
byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(paramString));
string verifyMessage = BitConverter.ToString(hash).Replace("-", "").ToLower();
}
Step 2: Build iFrame URL
The string can now be appended to either the ‘hosted’ or ‘embedded’ endpoints using a ‘?’.
const baseUrl =
"https://sandbox.connectedpayments.commbank.com.au/es-client-frontend/hosted";
const iframeUrl = `${baseUrl}?${paramString}&verifyMessage=${verifyMessage}`;
Your assembled URL will look like this for the Hosted Implementation:
https://sandbox.connectedpayments.commbank.com.au/es-client-frontend/hosted?configId=5f06c5f5-d4cb-483b-b0b2-242f48516dc5&userName=merchant.iframes&txnType=1&merchReference=ORDER-12345&amount=1000&verifyMessage=abc123def456...
Your assembled URL will look like this for the Embedded Implementation:
https://sandbox.connectedpayments.commbank.com.au/es-client-frontend/embedded?configId=5f06c5f5-d4cb-483b-b0b2-242f48516dc5&userName=merchant.iframes&txnType=1&merchReference=ORDER-12345&amount=1000&verifyMessage=abc123def456...
Step 3: Implement client
Choose how to display the payment form to your customers. Use the embedded iFrame for a seamless in-page experience, or redirect to the hosted page for a full-screen checkout flow.
Option A: Embedded iFrame
<iframe
id="connectedpayments-iframe"
src="YOUR_GENERATED_URL"
width="100%"
height="600px"
frameborder="0"
allow="payment"
>
</iframe>
Option B: Hosted (Redirect)
window.location.href = iframeUrl;
Step 4: Handle response
Set up a webhook endpoint to receive payment results from Connected Payments. This server-to-server notification is the most reliable way to process successful payments and update your order status.
// Webhook endpoint (recommended)
app.post("/webhook", express.json(), (req, res) => {
// Validate signature
if (!validateSignature(req.body, req.headers["x-signature"])) {
return res.status(401).send("Invalid signature");
}
// Process payment result
if (req.body.responseCode === "00") {
fulfillOrder(req.body.merchReference);
}
// Acknowledge receipt
res.status(200).send("OK");
});
Complete example
View full Node.js implementation
// server.js
const express = require("express");
const crypto = require("crypto");
const app = express();
const CONFIG = {
configId: "5f06c5f5-d4cb-483b-b0b2-242f48516dc5",
userName: "merchant.iframes",
secretKey: process.env.CONNECTED_PAYMENTS_SECRET_KEY,
baseUrl:
"https://sandbox.connectedpayments.commbank.com.au/es-client-frontend/hosted",
};
function generateIframeUrl(orderData) {
const params = {
configId: CONFIG.configId,
userName: CONFIG.userName,
txnType: 1,
merchReference: orderData.reference,
amount: orderData.amount,
};
// Add optional parameters
if (orderData.returnUrl) params.returnUrl = orderData.returnUrl;
if (orderData.email) params.email = orderData.email;
// Create parameter string (required params only)
const paramString = `configId=${params.configId}&userName=${params.userName}&txnType=${params.txnType}&merchReference=${params.merchReference}&amount=${params.amount}`;
// Generate HMAC
const verifyMessage = crypto
.createHmac("sha256", CONFIG.secretKey)
.update(paramString)
.digest("hex");
// Build complete URL
const urlParams = new URLSearchParams(params);
urlParams.append("verifyMessage", verifyMessage);
return `${CONFIG.baseUrl}?${urlParams.toString()}`;
}
// Payment page
app.get("/checkout/:orderId", async (req, res) => {
const order = await getOrder(req.params.orderId);
const iframeUrl = generateIframeUrl({
reference: `ORDER-${order.id}-${Date.now()}`,
amount: order.total * 100,
returnUrl: `${process.env.APP_URL}/payment/return`,
email: order.customerEmail,
});
res.render("checkout", { iframeUrl });
});
// Webhook handler
app.post("/webhook", express.json(), (req, res) => {
if (!validateSignature(req.body, req.headers["x-signature"])) {
return res.status(401).send("Invalid signature");
}
if (req.body.responseCode === "00") {
updateOrder(req.body.merchReference, "paid");
fulfillOrder(req.body.merchReference);
} else {
updateOrder(req.body.merchReference, "failed");
}
res.status(200).send("OK");
});
app.listen(3000);
View full PHP implementation
<?php
function generateIframeUrl($orderData) {
$config = [
'configId' => '5f06c5f5-d4cb-483b-b0b2-242f48516dc5',
'userName' => 'merchant.iframes',
'secretKey' => getenv('CONNECTED_PAYMENTS_SECRET_KEY'),
'baseUrl' => 'https://sandbox.connectedpayments.commbank.com.au/es-client-frontend/hosted'
];
$params = [
'configId' => $config['configId'],
'userName' => $config['userName'],
'txnType' => 1,
'merchReference' => $orderData['reference'],
'amount' => $orderData['amount']
];
$paramString = http_build_query($params);
$verifyMessage = hash_hmac('sha256', $paramString, $config['secretKey']);
$params['verifyMessage'] = $verifyMessage;
return $config['baseUrl'] . '?' . http_build_query($params);
}
$order = getOrder($_GET['orderId']);
$iframeUrl = generateIframeUrl([
'reference' => 'ORDER-' . $order['id'] . '-' . time(),
'amount' => $order['total'] * 100,
'returnUrl' => 'https://yoursite.com/payment/return',
'email' => $order['email']
]);
?>
<!DOCTYPE html>
<html>
<body>
<iframe src="<?php echo htmlspecialchars($iframeUrl); ?>" width="100%" height="600px"></iframe>
</body>
</html>
View full Python implementation
import hmac
import hashlib
from urllib.parse import urlencode
from flask import Flask, render_template
import os
app = Flask(__name__)
CONFIG = {
'config_id': '5f06c5f5-d4cb-483b-b0b2-242f48516dc5',
'user_name': 'merchant.iframes',
'secret_key': os.getenv('CONNECTED_PAYMENTS_SECRET_KEY'),
'base_url': 'https://sandbox.connectedpayments.commbank.com.au/es-client-frontend/hosted'
}
def generate_iframe_url(order_data):
params = {
'configId': CONFIG['config_id'],
'userName': CONFIG['user_name'],
'txnType': 1,
'merchReference': order_data['reference'],
'amount': order_data['amount']
}
param_string = '&'.join([f"{k}={v}" for k, v in params.items()])
verify_message = hmac.new(
CONFIG['secret_key'].encode(),
param_string.encode(),
hashlib.sha256
).hexdigest()
params['verifyMessage'] = verify_message
return f"{CONFIG['base_url']}?{urlencode(params)}"
@app.route('/checkout/<order_id>')
def checkout(order_id):
order = get_order(order_id)
iframe_url = generate_iframe_url({
'reference': f'ORDER-{order["id"]}-{int(time.time())}',
'amount': int(order['total'] * 100),
'email': order['email']
})
return render_template('checkout.html', iframe_url=iframe_url)
Handle responses
- Webhook / Notifications
- Redirect URL
- PostMessages
Server-to-server webhooks provide reliable, authoritative payment results.
How it works:
- Payment is processed
- Connected Payments sends an HTTPS POST to your notification endpoint
- Your server validates the signature and processes the result
- Your server responds with HTTP 200 to acknowledge receipt
View webhook implementation example
app.post("/webhook", express.json(), (req, res) => {
// 1. Validate signature
const signature = req.headers["x-signature"];
if (!isValidSignature(req.body, signature)) {
return res.status(401).end();
}
// 2. Process payment result
const { responseCode, merchReference, txnReference } = req.body;
if (responseCode === "00") {
// Payment successful
fulfillOrder(merchReference);
sendConfirmationEmail(merchReference);
} else {
// Payment failed
notifyCustomer(merchReference, "Payment declined");
}
// 3. Acknowledge receipt (must return 200)
res.status(200).send("OK");
});
Configuration: Webhooks are configured in your iFrame config. Contact CommBank Support to set up.
For Hosted integration only
Use for immediate customer feedback after hosted iFrame payment.
View redirect URL implementation example
// In your iFrame URL generation
params.returnUrl = "https://yoursite.com/payment/return";
// Handle return
app.get("/payment/return", (req, res) => {
// Validate signature before trusting data
if (!validateReturnSignature(req.query)) {
return res.redirect("/payment/error");
}
if (req.query.responseCode === "00") {
res.redirect("/payment/success");
} else {
res.redirect("/payment/declined");
}
});
For Embedded integration only
Listen for real-time updates from the iFrame. Use for UI feedback — never as authoritative payment confirmation.
Benefits:
- Real-time updates and field-level validation feedback
- Immediate user experience feedback
Limitations:
- Dependent on customer's browser
- Can be blocked by browser settings
- Not suitable as authoritative source
View PostMessages implementation example
window.addEventListener("message", (event) => {
// Validate origin
if (event.origin !== "https://sandbox.connectedpayments.commbank.com.au") {
return;
}
const message = event.data;
if (message.info === "paymentOutcome") {
if (message.responseCode === "00") {
showSuccess(message.txnReference);
} else {
showError(message.responseText);
}
}
});
See also: PostMessages Guide
Response handling comparison
| Method | Use Case | Validation |
|---|---|---|
| Webhook | Authoritative payment processing | Signature required |
| Redirect | Immediate user feedback (hosted) | Signature required |
| PostMessage | Real-time UI updates (embedded) | Origin check only |
Approach:
- Primary: Use webhooks/notifications for authoritative payment processing
- Secondary: Use redirects or PostMessages for immediate user feedback
- Always: Validate signatures on webhooks and redirects
- Never: Process orders based solely on PostMessages
Configuration reference
Environments
| Environment | Hosted URL | Embedded URL |
|---|---|---|
| Sandbox | https://sandbox.connectedpayments.commbank.com.au/es-client-frontend/hosted | https://sandbox.connectedpayments.commbank.com.au/es-client-frontend/embedded |
| Production | https://connectedpayments.commbank.com.au/es-client-frontend/hosted | https://connectedpayments.commbank.com.au/es-client-frontend/embedded |
Parameters
- Required
- Optional
- Platform Partners
| Parameter | Type | Description | Example |
|---|---|---|---|
configId | string | Your iFrame configuration ID. You can have multiple IDs for different use cases. | '5f06c5f5-d4cb-483b-b0b2-242f48516dc5' |
userName | string | Connected Payments username with transaction permissions | 'merchant.iframes' |
txnType | integer | Transaction type (see transaction types below) | 1 |
merchReference | string | Unique transaction reference — duplicates will be rejected | 'ORDER-12345' |
amount | integer | Amount in cents (e.g. 1000 = $10.00, 9999 = $99.99) | 1000 |
verifyMessage | string | HMAC SHA-256 signature | 'abc123...' |
For merchReference, use a format like ORDER-{orderId}-{timestamp} or a UUID to guarantee uniqueness.
| Parameter | Type | Description | Default |
|---|---|---|---|
currency | string | 3-letter currency code | 'AUD' |
returnUrl | string | URL to redirect after payment | - |
email | string | Customer email address (mandatory when using 3DSecure) | - |
channel | string | The transactional channel for the transaction. Character limit of 200. | 'iframe' |
cardToken | string | Pre-existing token for saved cards | - |
onlyTokenise | boolean | Create token without charging | false |
metadata | object | Custom metadata (JSON) | {} |
As part of integrating with Connected Payments, platforms are required to identify themselves by providing a Platform name in the Channel field during connection or configuration.
The Channel field is used to indicate the originating platform or plug‑in (for example RMS, Xetta, or Nelnet) and is recorded against the connection. This value is then associated with all transactions initiated via that connection to support visibility across the Connected Payments ecosystem.
This requirement applies to all Connected Payments platform integrations.
| Parameter | Type | Description | Example |
|---|---|---|---|
channel | string | Captures the platform name used to connect to Connected Payments. This value identifies the originating platform and is stored against the associated transaction to support platform visibility, reporting and operational support. | 'Platform Name' |
Transaction types
| Value | Type | Description |
|---|---|---|
1 | Purchase | Standard payment |
9 | Capture | Capture pre-authorized funds |
10 | Pre-Auth | Hold funds without charging |
20 | Refund | Refund against original transaction |
21 | Open Refund | Refund without original transaction |
30 | Void | Cancel transaction before settlement |
39 | Reversal | Reverse a transaction |
Testing
For test credentials, test cards, and integration verification steps, see the Testing Guide.